package com.immediatus.util;

import java.io.Serializable;

public class Vector2 implements Serializable {
    static public final float PI = 3.1415927f;
    static public final float RADIANS_TO_DEGREES = 180f / PI;
    static public final float DEGREES_TO_RADIANS = PI / 180;

	private final static Vector2 _tmp = new Vector2();
	public float _x;
	public float _y;

	public Vector2 () {
	}

	public Vector2 (float x_, float y_) {
		this._x = x_;
		this._y = y_;
	}

	public Vector2 (Vector2 v_) {
		set(v_);
	}

	public Vector2 cpy () {
		return new Vector2(this);
	}

	public float len () {
		return (float)Math.sqrt(this._x * this._x + this._y * this._y);
	}

	public float len2 () {
		return this._x * this._x + this._y * this._y;
	}

	public Vector2 set (Vector2 v_) {
        this._x = v_._x;
        this._y = v_._y;
		return this;
	}

	public Vector2 set (float x_, float y_) {
		this._x = x_;
		this._y = y_;
		return this;
	}

	public Vector2 sub (Vector2 v_) {
        this._x -= v_._x;
        this._y -= v_._y;
		return this;
	}

	public Vector2 nor () {
		float len = len();
		if (len != 0) {
            this._x /= len;
            this._y /= len;
		}
		return this;
	}

	public Vector2 add (Vector2 v_) {
        this._x += v_._x;
        this._y += v_._y;
		return this;
	}

	public Vector2 add (float x_, float y_) {
        this._x += x_;
		this._y += y_;
		return this;
	}

	public float dot (Vector2 v_) {
		return this._x * v_._x + this._y * v_._y;
	}

	public Vector2 mul (float scalar_) {
        this._x *= scalar_;
        this._y *= scalar_;
		return this;
	}

	public float dst (Vector2 v_) {
		final float x_d = v_._x - this._x;
		final float y_d = v_._y - this._y;
		return (float)Math.sqrt(x_d * x_d + y_d * y_d);
	}

	public float dst (float x_, float y_) {
		final float x_d = x_ - this._x;
		final float y_d = y_ - this._y;
		return (float)Math.sqrt(x_d * x_d + y_d * y_d);
	}

	public float dst2 (Vector2 v_) {
		final float x_d = v_._x - this._x;
		final float y_d = v_._y - this._y;
		return x_d * x_d + y_d * y_d;
	}

	public Vector2 sub (float x_, float y_) {
		this._x -= x_;
		this._y -= y_;
		return this;
	}

	public Vector2 tmp () {
		return _tmp.set(this);
	}

	public Vector2 mul (float[] m_) {
		float x = this._x * m_[0] + this._y * m_[3] + m_[6];
		float y = this._x * m_[1] + this._y * m_[4] + m_[7];
		this._x = x;
		this._y = y;
		return this;
	}

	public float crs (Vector2 v_) {
		return this._x * v_._y - this._y * v_._x;
	}

	public float crs (float x_, float y_) {
		return this._x * y_ - this._y * x_;
	}

	public float angle () {
		float angle = (float)Math.atan2(this._y, this._x) * RADIANS_TO_DEGREES;
		if (angle < 0) angle += 360;
		return angle;
	}

	public Vector2 rotate (float angle_) {
		float rad = angle_ * DEGREES_TO_RADIANS;
		float cos = (float)Math.cos(rad);
		float sin = (float)Math.sin(rad);

		float newX = this._x * cos - this._y * sin;
		float newY = this._x * sin + this._y * cos;

		this._x = newX;
		this._y = newY;

		return this;
	}

	public Vector2 lerp (Vector2 target_, float alpha_) {
		Vector2 r = this.mul(1.0f - alpha_);
		r.add(target_.tmp().mul(alpha_));
		return r;
	}
}
